package com.eternal.base.protocol;

import com.clj.fastble.data.BleDevice;
import com.eternal.base.concat.DeviceMinModel;
import com.eternal.base.concat.DeviceModel;
import com.eternal.base.concat.DeviceModelTime;
import com.eternal.base.concat.DeviceSetting;
import com.eternal.base.concat.DeviceTFP;
import com.eternal.base.database.entity.Device;
import com.eternal.base.database.entity.History;
import com.eternal.base.database.entity.Log;
import com.eternal.base.database.entity.Notification;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.utils.ByteUtils;
import com.eternal.base.utils.CRCUtil;
import com.eternal.base.utils.ScanRecord;
import com.eternal.framework.utils.KLog;
import com.google.android.material.appbar.AppBarLayout;
import com.google.common.primitives.UnsignedBytes;

import java.nio.charset.StandardCharsets;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator
 * On 2020/4/26
 * Description: 蓝牙交互命令
 *
 * @author Administrator
 */
public class ProtocolResolution {
    private static final int SCAN_RECORD_LENGTH = 27;
    private static final byte[] HEAD = new byte[]{(byte) 0xA5, 0x00};

    /**
     * 获得查询温度单位
     *
     * @param sequence 序列
     * @return 包
     */
    public static byte[] getTempUnitData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_TMP_UNIT,
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    /**
     * 获得查询温度，负载，等包数据
     *
     * @param command  查询方式
     * @param sequence 序列
     * @return 包
     */
    public static byte[] getTFPData(byte command, int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_CURRENT_TEMP_HUM_STATUS,
                BluetoothKey.DEVICE_CURRENT_LOAD_CONDITION,
                BluetoothKey.DEVICE_TMP_UNIT
        }, command, sequence);
    }

    public static byte[] getSettingData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_TMP_UNIT,
                BluetoothKey.DEVICE_BACKLIGHT_BRINGHTNESS_GEAR,
                BluetoothKey.DEVICE_TEMP_HUM_TRANSITION,
                BluetoothKey.DEVICE_TEMP_HUM_CALIBRATION,
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getBSettingData(int sequence){
        return addHead(new byte[]{
                BluetoothKey.DEVICE_TMP_UNIT,
                BluetoothKey.DEVICE_BACKLIGHT_BRINGHTNESS_GEAR,
                BluetoothKey.DEVICE_TEMP_HUM_BUFFER,
                BluetoothKey.DEVICE_TEMP_HUM_CALIBRATION,
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getCSettingData(int sequence){
        return addHead(new byte[]{
                BluetoothKey.DEVICE_TMP_UNIT,
                BluetoothKey.DEVICE_BACKLIGHT_BRINGHTNESS_GEAR,
                BluetoothKey.DEVICE_TEMP_HUM_CALIBRATION
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_CURRENT_OPERATING_MODE,
                BluetoothKey.DEVICE_CURRENT_TEMP_HUM_STATUS,
                BluetoothKey.DEVICE_CURRENT_LOAD_CONDITION,
                BluetoothKey.DEVICE_TMP_UNIT
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getOffModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_FAN_GEAR_BY_OFF
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getOnModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_FAN_GEAR_BY_ON
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getAutoModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_TEMP_HUM_STATUS_BY_AUTO
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getTimeOnModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_DURATION_BY_TIMER_TO_ON,
                BluetoothKey.DEVICE_TIME_REMAINING_BY_CURRENT_MODE
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getTimeOffModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_DURATION_BY_TIMER_TO_OFF,
                BluetoothKey.DEVICE_TIME_REMAINING_BY_CURRENT_MODE
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getCycleModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_DURATION_BY_CYCLE,
                BluetoothKey.DEVICE_TIME_REMAINING_BY_CURRENT_MODE
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getSchedModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_DURATION_BY_SCHED
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getAllModelData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_CURRENT_OPERATING_MODE,
                BluetoothKey.DEVICE_FAN_GEAR_BY_OFF,
                BluetoothKey.DEVICE_FAN_GEAR_BY_ON,
                BluetoothKey.DEVICE_TEMP_HUM_STATUS_BY_AUTO,
                BluetoothKey.DEVICE_DURATION_BY_TIMER_TO_ON,
                BluetoothKey.DEVICE_DURATION_BY_TIMER_TO_OFF,
                BluetoothKey.DEVICE_DURATION_BY_CYCLE,
                BluetoothKey.DEVICE_DURATION_BY_SCHED
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getNotificationData(int sequence) {
        return addHead(new byte[]{
                BluetoothKey.DEVICE_SET_THE_RELEVANT_AUTOMATION_MESSAGE,
                BluetoothKey.DEVICE_SET_THE_RELEVANT_ALARM_MESSAGE,
                BluetoothKey.DEVICE_SET_THE_RELEVANT_NOTIFICATION_MESSAGE
        }, BluetoothKey.COMMAND_GET, sequence);
    }

    public static byte[] getLogStart(long start, long now, int id, int sequence) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(start);
        byte[] data = new byte[14];
        data[0] = (byte) (calendar.get(Calendar.YEAR) - 2000);
        data[1] = (byte) (calendar.get(Calendar.MONTH)+1);
        data[2] = (byte) calendar.get(Calendar.DAY_OF_MONTH);
        data[3] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
        data[4] = (byte) calendar.get(Calendar.MINUTE);
        data[5] = (byte) calendar.get(Calendar.SECOND);
        int sub= (int) (TimeUnit.MILLISECONDS.toSeconds(now)-TimeUnit.MILLISECONDS.toSeconds(start));
        data[6] = (byte) ((sub >> 24) & 0xff);
        data[7] = (byte) ((sub >> 16) & 0xff);
        data[8] = (byte) ((sub >> 8) & 0xff);
        data[9] = ((byte) (sub & 0xff));
        data[10] = (byte) ((id >> 24) & 0xff);
        data[11] = (byte) ((id >> 16) & 0xff);
        data[12] = (byte) ((id >> 8) & 0xff);
        data[13] = (byte) (id & 0xff);
        return addHead(data, BluetoothKey.COMMAND_LOG_START, sequence);
    }

    public static byte[] getHistoryStart(long start, long now, int sequence) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(start);
        byte[] data = new byte[10];
        data[0] = (byte) (calendar.get(Calendar.YEAR) - 2000);
        data[1] = (byte) (calendar.get(Calendar.MONTH)+1);
        data[2] = (byte) calendar.get(Calendar.DAY_OF_MONTH);
        data[3] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
        data[4] = (byte) calendar.get(Calendar.MINUTE);
        data[5] = (byte) calendar.get(Calendar.SECOND);
        int sub = (int) (TimeUnit.MILLISECONDS.toSeconds(now)- TimeUnit.MILLISECONDS.toSeconds(start));
        data[6] = (byte) ((sub >> 24) & 0xff);
        data[7] = (byte) ((sub >> 16) & 0xff);
        data[8] = (byte) ((sub >> 8) & 0xff);
        data[9] = ((byte) (sub & 0xff));
        return addHead(data, BluetoothKey.COMMAND_HISTORY_START, sequence);
    }

    public static byte[] getLog(int max, int index, int sequence) {
        byte[] data = new byte[8];
        data[0] = (byte) ((max >> 24) & 0xff);
        data[1] = (byte) ((max >> 16) & 0xff);
        data[2] = (byte) ((max >> 8) & 0xff);
        data[3] = (byte) (max & 0xff);
        data[4] = (byte) ((index >> 24) & 0xff);
        data[5] = (byte) ((index >> 16) & 0xff);
        data[6] = (byte) ((index >> 8) & 0xff);
        data[7] = (byte) (index & 0xff);
        return addHead(data, BluetoothKey.COMMAND_LOG, sequence);
    }

    public static byte[] getHistory(int max, int index, int sequence) {
        byte[] data = new byte[8];
        data[0] = (byte) ((max >> 24) & 0xff);
        data[1] = (byte) ((max >> 16) & 0xff);
        data[2] = (byte) ((max >> 8) & 0xff);
        data[3] = (byte) (max & 0xff);
        data[4] = (byte) ((index >> 24) & 0xff);
        data[5] = (byte) ((index >> 16) & 0xff);
        data[6] = (byte) ((index >> 8) & 0xff);
        data[7] = (byte) (index & 0xff);
        return addHead(data, BluetoothKey.COMMAND_HISTORY, sequence);
    }

    public static byte[] getLogEnd(int sequence) {
        return addHead(new byte[0], BluetoothKey.COMMAND_LOG_END, sequence);
    }

    public static byte[] getHistoryEnd(int sequence) {
        return addHead(new byte[0], BluetoothKey.COMMAND_HISTORY_END, sequence);
    }

    public static byte[] setSettingData(DeviceSetting setting, int sequence) {
        byte[] data = new byte[16];
        //温度单位
        data[0] = 0x20;
        data[1] = 0x1;
        data[2] = (byte) (setting.isDegree ? 0x1 : 0x0);
        //背光亮度
        data[3] = 0x21;
        data[4] = 0x1;
        data[5] = setting.brightness;
        //transition 温度和湿度
        data[6] = 0x22;
        data[7] = 0x3;
        data[8] = 0x0;
        data[9] = 0x0;
        data[10] = setting.transitionHumidity;
        if (setting.isDegree) {
            data[9] = setting.transitionTemperature;
        } else {
            data[8] = setting.transitionTemperature;
        }
        //
        data[11] = 0x24;
        data[12] = 0x3;
        data[13] = 0x0;
        data[14] = 0x0;
        data[15] = setting.calibrationHumidity;
        if (setting.isDegree) {
            data[14] = setting.calibrationTemperature;
        } else {
            data[13] = setting.calibrationTemperature;
        }
        return addHead(data, BluetoothKey.COMMAND_SET, sequence);
    }

    public static byte[] setBSettingData(DeviceSetting setting, int sequence){
        byte[] data = new byte[16];
        //温度单位
        data[0] = 0x20;
        data[1] = 0x1;
        data[2] = (byte) (setting.isDegree ? 0x1 : 0x0);
        //背光亮度
        data[3] = 0x21;
        data[4] = 0x1;
        data[5] = setting.brightness;
        //buffer 温度和湿度
        data[6] = 0x23;
        data[7] = 0x3;
        data[10] = setting.transitionHumidity;
        if (setting.isDegree) {
            data[8] = (byte) Math.round(ProtocolTransformer.getFah(setting.transitionTemperature));
            data[9] = setting.transitionTemperature;
        } else {
            data[8] = setting.transitionTemperature;
            data[9] = (byte) Math.round(ProtocolTransformer.getDegree(setting.transitionTemperature));
        }
        //calibration 温湿度
        data[11] = 0x24;
        data[12] = 0x3;
        data[13] = 0x0;
        data[14] = 0x0;
        data[15] = setting.calibrationHumidity;
        if (setting.isDegree) {
            data[13] = (byte) Math.round(ProtocolTransformer.getFah(setting.calibrationTemperature));
            data[14] = setting.calibrationTemperature;
        } else {
            data[13] = setting.calibrationTemperature;
            data[14] = (byte) Math.round(ProtocolTransformer.getDegree(setting.calibrationTemperature));
        }
        return addHead(data, BluetoothKey.COMMAND_SET, sequence);
    }

    public static byte[] setCSettingData(DeviceSetting setting, int sequence){
        byte[] data = new byte[11];
        //温度单位
        data[0] = 0x20;
        data[1] = 0x1;
        data[2] = (byte) (setting.isDegree ? 0x1 : 0x0);
        //背光亮度
        data[3] = 0x21;
        data[4] = 0x1;
        data[5] = setting.brightness;
        //calibration 温湿度
        data[6] = 0x24;
        data[7] = 0x3;
        data[10] = setting.calibrationHumidity;
        if (setting.isDegree) {
            data[8] = (byte) Math.round(ProtocolTransformer.getFah(setting.calibrationTemperature));
            data[9] = setting.calibrationTemperature;
        } else {
            data[8] = setting.calibrationTemperature;
            data[9] = (byte) Math.round(ProtocolTransformer.getDegree(setting.calibrationTemperature));
        }
        return addHead(data, BluetoothKey.COMMAND_SET, sequence);
    }



    public static byte[] setModelData(DeviceModel model, int sequence) {
        byte[] packet;
        switch (model.workType) {
            case BluetoothKey.MODE_OFF:
                packet = new byte[]{0x11, 0x1, model.typeOff};
                break;
            case BluetoothKey.MODE_ON:
                packet = new byte[]{0x12, 0x1, model.typeOn};
                break;
            case BluetoothKey.MODE_AUTO:
                if (model.isDegree) {
                    packet = new byte[]{0x13, 0x7, ProtocolTransformer.getTmpSwitch(model),
                            (byte) Math.round(ProtocolTransformer.getFah(model.autoHighTmp)), model.autoHighTmp,
                            (byte) Math.round(ProtocolTransformer.getFah(model.autoLowTmp)), model.autoLowTmp,
                            model.autoHighHum, model.autoLowHum};
                } else {
                    packet = new byte[]{0x13, 0x7, ProtocolTransformer.getTmpSwitch(model),
                            model.autoHighTmp, (byte) Math.round(ProtocolTransformer.getDegree(UnsignedBytes.toInt(model.autoHighTmp))),
                            model.autoLowTmp, (byte) Math.round(ProtocolTransformer.getDegree(UnsignedBytes.toInt(model.autoLowTmp))),
                            model.autoHighHum, model.autoLowHum};
                }
                break;
            case BluetoothKey.MODE_TIME_OFF:
                packet = new byte[6];
                packet[0] = 0x15;
                packet[1] = 4;
                int value = model.timeOff * 60;
                setSecond(packet, 2, value);
                break;
            case BluetoothKey.MODE_TIME_ON:
                packet = new byte[6];
                packet[0] = 0x14;
                packet[1] = 4;
                value = model.timeOn * 60;
                setSecond(packet, 2, value);
                break;
            case BluetoothKey.MODE_CYCLE:
                packet = new byte[10];
                packet[0] = 0x16;
                packet[1] = 8;
                value = model.cycleOn * 60;
                setSecond(packet, 2, value);
                value = model.cycleOff * 60;
                setSecond(packet, 6, value);
                break;
            default:
                packet = new byte[6];
                packet[0] = 0x17;
                packet[1] = 4;
                value = model.schedOn;
                if (value == 1440) {
                    value = 1439;
                }
                packet[2] = (byte) (value / 60);
                packet[3] = (byte) (value % 60);
                value = model.schedOff;
                if (value == 1440) {
                    value = 1439;
                }
                packet[4] = (byte) (value / 60);
                packet[5] = (byte) (value % 60);
        }
        return addHead(packet, BluetoothKey.COMMAND_SET, sequence);
    }

    public static byte[] setModelData(byte model, int sequence) {
        return addHead(new byte[]{
                0x10, 1, model
        }, BluetoothKey.COMMAND_SET, sequence);
    }

    private static void setSecond(byte[] data, int start, int seconds) {
        data[start] = (byte) (seconds >> 24 & 0xff);
        data[start + 1] = (byte) (seconds >> 16 & 0xff);
        data[start + 2] = (byte) (seconds >> 8 & 0xff);
        data[start + 3] = (byte) (seconds & 0xff);
    }

    /**
     * 格式化设置是否存在，开启状态等为Advance需要发送到byte
     *
     * @param isExists 是否存在
     * @param isOpen   是否打开
     * @param seridNo
     * @return
     */
    public static byte formatBitForAdvance(boolean isExists, boolean isOpen, int seridNo) {
        byte b = 0;
        b = (byte) ((b >> 7 | (isExists ? 1 : 0)) << 7);
        b = (byte) ((b >> 6 | (isOpen ? 1 : 0)) << 6);
        return (byte) (b | seridNo);
    }

    public static byte[] setNotificationData(Notification notification, boolean isExists, boolean isOpen, int sequence) {
        byte[] packet;
        if (notification.type == BluetoothKey.AUTOMATION) {
            packet = new byte[24];
            packet[0] = 0x31;
            packet[1] = 22;
            packet[2] = formatBitForAdvance(isExists, isOpen, notification.id);
            packet[3] = (byte) notification.id;
            packet[4] = (byte) (notification.start / 60);
            packet[5] = (byte) (notification.start % 60);
            packet[6] = (byte) (notification.end / 60);
            packet[7] = (byte) (notification.end % 60);
            packet[8] = notification.model;
            int value = notification.cycleOn * 60;
            packet[9] = (byte) (value >> 24);
            packet[10] = (byte) (value >> 16);
            packet[11] = (byte) (value >> 8);
            packet[12] = (byte) value;
            value = notification.cycleOff * 60;
            packet[13] = (byte) (value >> 24);
            packet[14] = (byte) (value >> 16);
            packet[15] = (byte) (value >> 8);
            packet[16] = (byte) value;
            packet[17] = notification.tmpHum;
            packet[18] = notification.hTmpF;
            packet[19] = notification.hTmpC;
            packet[20] = notification.lTmpF;
            packet[21] = notification.lTmpC;
            packet[22] = notification.hHum;
            packet[23] = notification.lHum;
        } else {
            packet = new byte[13];
            if (notification.type == BluetoothKey.ALARMS) {
                packet[0] = 0x32;
            } else {
                packet[0] = 0x33;
            }
            packet[1] = 11;
            packet[2] = formatBitForAdvance(isExists, isOpen, notification.id);
            packet[3] = notification.model;
            packet[4] = notification.tmpHum;
            packet[5] = notification.hTmpF;
            packet[6] = notification.hTmpC;
            packet[7] = notification.lTmpF;
            packet[8] = notification.lTmpC;
            packet[9] = notification.hHum;
            packet[10] = notification.lHum;
            packet[11] = 0;
            packet[12] = 0;
        }
        return addHead(packet, BluetoothKey.COMMAND_SET, sequence);
    }

    /**
     * 格式化数据为A5打头的数据包
     * 首字节 + 占位 + 数据长度 + 序号 + 校验码 + 占位符 + Command + 数据 + 校验码
     *
     * @param data        需要转换的数据包
     * @param commandType 命令  hex0x01--int-1--读取设备数据  hex0x02--int-2--读取设备数据（仅回复变化数据)
     *                    hex0x03--int-3--设置一个多个数据 hex0x11--int-17---读取历史日志
     *                    hex0x12--int-18--读取一组历史日志  hex0x13--int-19--结束读取历史日志
     *                    hex0x14--int-20--读取历史温湿度数据  hex0x15--int-21--读取一组温湿度数据
     *                    hex0x16--int-22--结束读取温湿度数据  hex-0x31--int-49--一组Automation
     *                    hex-0x32--int-50--一组Alarm hex-0x33--int-51--一组Notification
     * @return
     */
    static byte[] addHead(byte[] data, byte commandType, int sequence) {
        byte[] packet = new byte[12 + data.length];
        //固定头
        System.arraycopy(HEAD, 0, packet, 0, HEAD.length);
        //数据长度字节数组
        addInit(packet, 2, data.length);
        //当前数据序号字节数组
        addInit(packet, 4, sequence);
        //crc1
        byte[] crc = CRCUtil.crc16(packet, 0, 6);
        System.arraycopy(crc, 0, packet, 6, 2);
        //命令
        packet[8] = 0x00;
        packet[9] = commandType;
        //数据
        System.arraycopy(data, 0, packet, 10, data.length);
        //crc2
        crc = CRCUtil.crc16(packet, 8, 2 + data.length);
        System.arraycopy(crc, 0, packet, 10 + data.length, 2);
        return packet;
    }

    private static List<byte[]> getListIntArray(byte[] data, int length) {
        //拆分
        int size = data.length / length;
        //余数
        int remain = data.length % length;
        if (remain != 0) {
            ++size;
        }
        List<byte[]> result = new ArrayList<>(size);
        byte[] packet;
        for (int i = 0; i < size - 1; ++i) {
            packet = new byte[length];
            System.arraycopy(data, i * length, packet, 0, packet.length);
            result.add(packet);
        }
        if (remain != 0) {
            packet = new byte[remain];
            System.arraycopy(data, (size - 1) * length, packet, 0, remain);
            result.add(packet);
        }
        return result;
    }

    private static void addInit(byte[] data, int pos, int x) {
        byte hei = (byte) ((x >> 8) & 0xff);
        byte low = (byte) (x & 0xff);
        data[pos] = hei;
        data[pos + 1] = low;
    }

    public static byte[] setTimeData(int sequence) {
        byte[] timeData = new byte[9];
        Calendar calendar = Calendar.getInstance();
        timeData[0] = BluetoothKey.DEVICE_CLOCK_TIME;
        timeData[1] = 7;
        timeData[2] = (byte) (calendar.get(Calendar.YEAR) % 100);
        timeData[3] = (byte) (calendar.get(Calendar.MONTH) + 1);
        timeData[4] = (byte) calendar.get(Calendar.DAY_OF_MONTH);
        timeData[5] = (byte) calendar.get(Calendar.DAY_OF_WEEK);
        timeData[6] = (byte) calendar.get(Calendar.HOUR_OF_DAY);
        timeData[7] = (byte) calendar.get(Calendar.MINUTE);
        timeData[8] = (byte) calendar.get(Calendar.SECOND);
        return addHead(timeData, BluetoothKey.COMMAND_SET, sequence);
    }

    public static boolean checkResult(byte[] packet) {
        packet = check(packet);
        for (int i = 1; i < packet.length; i += 2) {
            if (packet[i] == 1) {
                return false;
            }
        }
        return true;
    }

    public static boolean checkSequence(byte[] packet, int sequence) {
        int num = (((packet[4] & 0xff) << 8) + (packet[5] & 0xff));
        KLog.e("check sequence:" + num + " sequence:" + sequence);
        return (((packet[4] & 0xff) << 8) + (packet[5] & 0xff)) == sequence;
    }

    public static Device parseScanRecordData(BleDevice bleDevice) {
        byte[] scanRecord = ScanRecord.parseFromBytes(bleDevice.getScanRecord())
                .getManufacturerSpecificData(BluetoothKey.FEATURES);
        Device device = new Device(bleDevice.getMac());
        if (scanRecord != null && SCAN_RECORD_LENGTH == scanRecord.length) {
            device.typeName = new String(scanRecord, 6, 5, StandardCharsets.US_ASCII);
            //解析设备类型码
            device.type = scanRecord[12];
            byte bt = scanRecord[13];
            //解析当前设备是否可以被添加
            if (ByteUtils.getBit(bt, 0)) {
                KLog.i("当前设备可以被添加");
            } else {
                KLog.i("当前设备不可以被添加");
            }
            //解析当前设备的温度单位
            device.isDegree = !ByteUtils.getBit(bt, 1);
            //解析当前设备风扇档位变化
            device.fanState = (byte) ByteUtils.getBits(bt, 2, 2);
            //解析当前设备温度变化情况
            device.tmpState = (byte) ByteUtils.getBits(bt, 4, 2);
            //解析当前设备湿度变化情况
            device.humState = (byte) ByteUtils.getBits(bt, 6, 2);
            //当前实时温度
            device.tmp = ByteUtils.getShort(scanRecord, 14);
            //解析当前湿度
            device.hum = ByteUtils.getShort(scanRecord, 16);
            //解析当前风扇档位
            device.fan = scanRecord[18];
            //解析当前时间
            device.connectTime = System.currentTimeMillis();
            return device;
        }
        return null;
    }

    public static DeviceTFP parseTFP(byte[] packet) {
        DeviceTFP result = new DeviceTFP();
        packet = check(packet);
        if (packet[0] == BluetoothKey.DEVICE_CURRENT_TEMP_HUM_STATUS) {
            result.tmpState = (byte) ByteUtils.getBits(packet[2], 4, 2);
            result.humState = (byte) ByteUtils.getBits(packet[2], 6, 2);
            result.tmp = ByteUtils.getShort(packet, 3);
            result.per = ByteUtils.getShort(packet, 5);
        } else {
            return null;
        }

        if (packet[7] == BluetoothKey.DEVICE_CURRENT_LOAD_CONDITION) {
            //解析风扇档位
            result.fan = ByteUtils.getBits(packet[10], 4, 4);
            //解析当前风扇上升下降趋势
            result.fanState = (byte) ByteUtils.getBits(packet[10], 0, 2);
        } else {
            return null;
        }

        if(packet.length==12){
            result.isDegree=!ByteUtils.getBit(packet[11], 7);
        }else if (packet[14] == BluetoothKey.DEVICE_TMP_UNIT) {
            result.isDegree = !ByteUtils.getBit(packet[16], 7);
        } else {
            return null;
        }
        return result;
    }

    public static DeviceSetting parseCSetting(byte[] packet){
        DeviceSetting setting = new DeviceSetting();
        packet = check(packet);
        if (packet[0] == BluetoothKey.DEVICE_TMP_UNIT) {
            setting.isDegree = !ByteUtils.getBit(packet[2], 7);
        } else {
            return null;
        }
        if (packet[3] == BluetoothKey.DEVICE_BACKLIGHT_BRINGHTNESS_GEAR) {
            setting.brightness = packet[5];
        } else {
            return null;
        }
        if (packet[6] == BluetoothKey.DEVICE_TEMP_HUM_CALIBRATION) {
            if (setting.isDegree) {
                setting.calibrationTemperature = packet[9];
            } else {
                setting.calibrationTemperature = packet[8];
            }
            setting.calibrationHumidity = packet[10];
        } else {
            return null;
        }
        return setting;
    }

    public static DeviceSetting parseSetting(byte[] packet) {
        DeviceSetting setting = new DeviceSetting();
        packet = check(packet);
        if (packet[0] == BluetoothKey.DEVICE_TMP_UNIT) {
            setting.isDegree = !ByteUtils.getBit(packet[2], 7);
        } else {
            return null;
        }
        if (packet[3] == BluetoothKey.DEVICE_BACKLIGHT_BRINGHTNESS_GEAR) {
            setting.brightness = packet[5];
        } else {
            return null;
        }
        if (packet[6] == BluetoothKey.DEVICE_TEMP_HUM_TRANSITION||packet[6]==BluetoothKey.DEVICE_TEMP_HUM_BUFFER) {
            if (setting.isDegree) {
                setting.transitionTemperature = packet[9];
            } else {
                setting.transitionTemperature = packet[8];
            }
            setting.transitionHumidity = packet[10];
        } else {
            return null;
        }
        if (packet[11] == BluetoothKey.DEVICE_TEMP_HUM_CALIBRATION) {
            if (setting.isDegree) {
                setting.calibrationTemperature = packet[14];
            } else {
                setting.calibrationTemperature = packet[13];
            }
            setting.calibrationHumidity = packet[15];
        } else {
            return null;
        }
        return setting;
    }

    public static boolean parseMinModel(DeviceMinModel model, byte[] packet) {
        packet = check(packet);
        if (packet[0] == BluetoothKey.DEVICE_CURRENT_OPERATING_MODE) {
            model.model = packet[2];
        } else {
            KLog.e("model err:" + ByteUtils.bytes2HexString(packet));
            return false;
        }
        if (packet[3] == BluetoothKey.DEVICE_CURRENT_TEMP_HUM_STATUS) {
            model.tmpState = (byte) ByteUtils.getBits(packet[5], 4, 2);
            model.humState = (byte) ByteUtils.getBits(packet[5], 6, 2);
            model.tmp = ByteUtils.getShort(packet, 6);
            model.per = ByteUtils.getShort(packet, 8);
        } else {
            KLog.e("model err:" + ByteUtils.bytes2HexString(packet));
            return false;
        }

        if (packet[10] == BluetoothKey.DEVICE_CURRENT_LOAD_CONDITION) {
            //解析风扇档位
            model.fan = ByteUtils.getBits(packet[13], 4, 4);
            //解析当前风扇上升下降趋势
            model.fanState = (byte) ByteUtils.getBits(packet[13], 0, 2);
        } else {
            KLog.e("model err:" + ByteUtils.bytes2HexString(packet));
            return false;
        }

        if (packet[17] == BluetoothKey.DEVICE_TMP_UNIT) {
            model.isDegree = !ByteUtils.getBit(packet[19], 7);
        } else {
            KLog.e("model err:" + ByteUtils.bytes2HexString(packet));
            return false;
        }
        return true;
    }

    public static boolean initDeviceMinModel(DeviceMinModel model, byte[] packet) {
        packet = check(packet);
        switch (model.model) {
            case BluetoothKey.MODE_OFF:
            case BluetoothKey.MODE_ON:
                model.values[0] = packet[2];
                return true;
            case BluetoothKey.MODE_AUTO:
                System.arraycopy(packet, 2, model.values, 0, 7);
                return true;
            case BluetoothKey.MODE_TIME_ON:
            case BluetoothKey.MODE_TIME_OFF:
                System.arraycopy(packet, 2, model.values, 0, 4);
                if (packet[6] == BluetoothKey.DEVICE_TIME_REMAINING_BY_CURRENT_MODE) {
                    DeviceModelTime time = new DeviceModelTime();
                    time.time = (packet[9] & 0xff) * 3600;
                    time.time += (packet[10] & 0xff) * 60;
                    time.time += (packet[11] & 0xff);
                    time.isOff = packet[12] == 0;
                    model.time = time;
                    return true;
                }
                break;
            case BluetoothKey.MODE_CYCLE:
                System.arraycopy(packet, 2, model.values, 0, 8);
                if (packet[10] == BluetoothKey.DEVICE_TIME_REMAINING_BY_CURRENT_MODE) {
                    DeviceModelTime time = new DeviceModelTime();
                    time.time = (packet[13] & 0xff) * 3600;
                    time.time += (packet[14] & 0xff) * 60;
                    time.time += packet[15] & 0xff;
                    time.isOff = packet[16] == 0;

                    model.time = time;
                    return true;
                }
                break;
            default:
                System.arraycopy(packet, 2, model.values, 0, 4);
                return true;
        }
        KLog.e("err packet:" + ByteUtils.bytes2HexString(packet));
        return false;
    }

    public static DeviceModel parseDeviceModel(byte[] packet) {
        packet = check(packet);
        DeviceModel deviceModel = new DeviceModel();
        deviceModel.workType = packet[2];
        deviceModel.typeOff = packet[5];
        deviceModel.typeOn = packet[8];
        deviceModel.autoHighTmpSwitch = !ByteUtils.getBit(packet[11], 4);
        deviceModel.autoLowTmpSwitch = !ByteUtils.getBit(packet[11], 5);
        deviceModel.autoHighHumSwitch = !ByteUtils.getBit(packet[11], 6);
        deviceModel.autoLowHumSwitch = !ByteUtils.getBit(packet[11], 7);
        deviceModel.autoHighTmp = packet[13];
        deviceModel.autoLowTmp = packet[15];
        deviceModel.autoHighHum = packet[16];
        deviceModel.autoLowHum = packet[17];
        int num = ((packet[21] & 0xff) << 16) | ((packet[22] & 0xff) << 8) | (packet[23] & 0xff);
        deviceModel.timeOn = (char) (num / 60);
        num = ((packet[27] & 0xff) << 16) | ((packet[28] & 0xff) << 8) | (packet[29] & 0xff);
        deviceModel.timeOff = (char) (num / 60);
        num = ((packet[33] & 0xff) << 16) | ((packet[34] & 0xff) << 8) | (packet[35] & 0xff);
        deviceModel.cycleOn = (char) (num / 60);
        num = ((packet[37] & 0xff) << 16) | ((packet[38] & 0xff) << 8) | (packet[39] & 0xff);
        deviceModel.cycleOff = (char) (num / 60);
        deviceModel.schedOn = (char) (Math.round((packet[42] * 60 + packet[43])));
        deviceModel.schedOff = (char) (Math.round((packet[44] * 60 + packet[45])));
        return deviceModel;
    }

    public static Notification parseNotification(byte[] packet, int i){
        Notification n = new Notification();
        n.id = ByteUtils.getBits(packet[i + 2], 2, 6);
        n.open = !ByteUtils.getBit(packet[i + 2], 1);
        if (packet[i] == BluetoothKey.DEVICE_SET_THE_RELEVANT_AUTOMATION_MESSAGE) {
            n.type = BluetoothKey.AUTOMATION;
            n.start = (char) (packet[i + 4] * 60 + packet[i + 5]);
            n.end = (char) (packet[i + 6] * 60 + packet[i + 7]);
            n.model = packet[i + 8];
            n.cycleOn = (char) ((((packet[i + 10] & 0xff) << 16) + ((packet[i + 11] & 0xff) << 8) + (packet[i + 12] & 0xff)) / 60);
            n.cycleOff = (char) ((((packet[i + 14] & 0xff) << 16) + ((packet[i + 15] & 0xff) << 8) + (packet[i + 16] & 0xff)) / 60);
            n.tmpHum = packet[i + 17];
            n.hTmpF = packet[i + 18];
            n.hTmpC = packet[i + 19];
            n.lTmpF = packet[i + 20];
            n.hTmpC = packet[i + 21];
            n.hHum = packet[i + 22];
            n.lHum = packet[i + 23];
        } else {
            if (packet[i] == BluetoothKey.DEVICE_SET_THE_RELEVANT_ALARM_MESSAGE) {
                n.type = BluetoothKey.ALARMS;
            } else {
                n.type = BluetoothKey.NOTIFICATIONS;
            }
            n.model = packet[i + 3];
            n.tmpHum = packet[i + 4];
            n.hTmpF = packet[i + 5];
            n.hTmpC = packet[i + 6];
            n.lTmpF = packet[i + 7];
            n.lTmpC = packet[i + 8];
            n.hHum = packet[i + 9];
            n.lHum = packet[i + 10];
        }
        return n;
    }

    public static List<Notification> parseNotifications(byte[] packet) {
        packet = check(packet);
        Notification n;
        List<Notification> list = new ArrayList<>();
        int i = 0;
        while (i < packet.length) {
            if (packet.length < i + 4) {
//                KLog.e("parse notification err");
                break;
            }
            if(packet[i+1]==0){
                i+=2;
                continue;
            }
            n = new Notification();
            n.id = ByteUtils.getBits(packet[i + 2], 2, 6);
            n.open = !ByteUtils.getBit(packet[i + 2], 1);
            if (packet[i] == BluetoothKey.DEVICE_SET_THE_RELEVANT_AUTOMATION_MESSAGE) {
                if (packet.length < i + 24) {
//                    KLog.e("parse notification err");
                    break;
                }
                n.type = BluetoothKey.AUTOMATION;
                n.start = (char) (packet[i + 4] * 60 + packet[i + 5]);
                n.end = (char) (packet[i + 6] * 60 + packet[i + 7]);
                n.model = packet[i + 8];
                n.cycleOn = (char) ((((packet[i + 10] & 0xff) << 16) + ((packet[i + 11] & 0xff) << 8) + (packet[i + 12] & 0xff)) / 60);
                n.cycleOff = (char) ((((packet[i + 14] & 0xff) << 16) + ((packet[i + 15] & 0xff) << 8) + (packet[i + 16] & 0xff)) / 60);
                n.tmpHum = packet[i + 17];
                n.hTmpF = packet[i + 18];
                n.hTmpC = packet[i + 19];
                n.lTmpF = packet[i + 20];
                n.lTmpC = packet[i + 21];
                n.hHum = packet[i + 22];
                n.lHum = packet[i + 23];
                i += 24;
            } else {
                if (packet.length < i + 13) {
//                    KLog.e("parse notification err");
                    break;
                }
                if (packet[i] == BluetoothKey.DEVICE_SET_THE_RELEVANT_ALARM_MESSAGE) {
                    n.type = BluetoothKey.ALARMS;
                } else {
                    n.type = BluetoothKey.NOTIFICATIONS;
                }
                n.model = packet[i + 3];
                n.tmpHum = packet[i + 4];
                n.hTmpF = packet[i + 5];
                n.hTmpC = packet[i + 6];
                n.lTmpF = packet[i + 7];
                n.lTmpC = packet[i + 8];
                n.hHum = packet[i + 9];
                n.lHum = packet[i + 10];
                i += 13;
            }
            list.add(n);
        }
        return list;
    }

    public static int parseLogSize(byte[] packet) {
        packet = check(packet);
        int size = 0;
        size += (packet[0] & 0xff) << 24;
        size += (packet[1] & 0xff) << 16;
        size += (packet[2] & 0xff) << 8;
        size += packet[3] & 0xff;
        return size;
    }

    public static Log parseLog(byte[] packet, int num, long now) {
        if (num + 28 > packet.length) {
            return null;
        }
        Log temp = new Log();
        if (packet[num] == 0) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(packet[num + 1], packet[num + 2], packet[num + 3],
                    packet[num + 4], packet[num + 5], packet[num + 6]);
            temp.time = calendar.getTimeInMillis();
        } else {
            temp.time = ((packet[num + 1] & 0xff) << 24) | ((packet[num + 2] & 0xff) << 16) |
                    ((packet[num + 3] & 0xff) << 8) | (packet[num + 4] & 0xff);
            temp.time=TimeUnit.MILLISECONDS.toSeconds(now)-temp.time;
            temp.time=TimeUnit.SECONDS.toMillis(temp.time);
        }
        temp.id = ((packet[num + 7] & 0xff) << 24) | ((packet[num + 8] & 0xff) << 16) |
                ((packet[num + 9] & 0xff) << 8) | (packet[num + 10] & 0xff);
        temp.logType = packet[num + 11];
        temp.notifyId = packet[num + 12];
        temp.start = ((char) (packet[num + 13] * 60 + packet[num + 14]));
        temp.end = ((char) (packet[num + 15] * 60 + packet[num + 16]));
        temp.model = packet[num + 17];
        switch (temp.model) {
            case 0x1:
            case 0x2:
                temp.fan = packet[num + 18];
                break;
            case 0x3:
            case 0x8:
                temp.tmpHum = packet[num + 18];
                temp.hTmpF = packet[num + 19];
                temp.hTmpC = packet[num + 20];
                temp.lTmpF = packet[num + 21];
                temp.lTmpC = packet[num + 22];
                temp.hHum = packet[num + 23];
                temp.lHum = packet[num + 24];
                temp.fan = packet[num + 25];
                break;
            case 0x4:
                int time = ((packet[num + 19] & 0xff) << 16) | ((packet[num + 20] & 0xff) << 8) | (packet[num + 21] & 0xff);
                temp.fan = packet[num + 22];
                temp.on = (char) (time / 60);
                break;
            case 0x5:
                time = ((packet[num + 19] & 0xff) << 16) | ((packet[num + 20] & 0xff) << 8) + (packet[num + 21] & 0xff);
                temp.fan = packet[num + 22];
                temp.off = (char) (time / 60);
                break;
            case 0x6:
                time = ((packet[num + 19] & 0xff) << 16) + ((packet[num + 20] & 0xff) << 8) + (packet[num + 21] & 0xff);
                temp.on = (char) (time / 60);
                time = ((packet[num + 23] & 0xff) << 16) + ((packet[num + 24] & 0xff) << 8) + (packet[num + 25] & 0xff);
                temp.off = (char) (time / 60);
                temp.isStart = packet[num + 26] != 0;
                temp.fan = packet[num + 27];
                break;
            case 0x7:
                temp.on = (char) (packet[num + 18] * 60 + packet[num + 19]);
                temp.off = ((char) (packet[num + 20] * 60 + packet[num + 21]));
                temp.isStart = packet[num + 22] == 0;
                temp.fan = packet[num + 23];
            default:

        }
        return temp;
    }

    public static Log parseCLog(byte[] packet, int num, long now){
        if (num + 19 > packet.length) {
            return null;
        }
        Log temp = new Log();
        if (packet[num] == 0) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(packet[num + 1], packet[num + 2], packet[num + 3],
                    packet[num + 4], packet[num + 5], packet[num + 6]);
            temp.time = calendar.getTimeInMillis();
        } else {
            temp.time = ((packet[num + 1] & 0xff) << 24) | ((packet[num + 2] & 0xff) << 16) |
                    ((packet[num + 3] & 0xff) << 8) | (packet[num + 4] & 0xff);
            temp.time=TimeUnit.MILLISECONDS.toSeconds(now)-temp.time;
            temp.time=TimeUnit.SECONDS.toMillis(temp.time);
        }
        temp.id = ((packet[num + 7] & 0xff) << 24) | ((packet[num + 8] & 0xff) << 16) |
                ((packet[num + 9] & 0xff) << 8) | (packet[num + 10] & 0xff);
        temp.model=packet[num+11];
        temp.tmpHum=packet[num+12];
        temp.hTmpF = packet[num + 13];
        temp.hTmpC = packet[num + 14];
        temp.lTmpF = packet[num + 15];
        temp.lTmpC = packet[num + 16];
        temp.hHum = packet[num + 17];
        temp.lHum = packet[num + 18];
        return temp;
    }

    public static History parseHistory(byte[] packet, int num, long now, boolean offDefault) {
        History history = new History();
        history.time = now;
        history.tmp = ByteUtils.getShort(packet,num);
        history.hum = ((char) (((packet[num + 2] & 0xff) << 8) | (packet[num + 3] & 0xff)));
        if(!offDefault){
            history.off=packet[num+4]==0;
        }
        return history;
    }

    static byte[] check(byte[] packet) {
        byte[] data = new byte[packet.length - 10 - 2];
        System.arraycopy(packet, 10, data, 0, data.length);
        return data;
    }

    public static Boolean parseTempUnit(byte[] packet) {
        packet = check(packet);
        if (packet[0] == BluetoothKey.DEVICE_TMP_UNIT) {
            return !ByteUtils.getBit(packet[2], 7);
        } else {
            return false;
        }
    }
}
